package com.heyiming.myoauth2;

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;

@RestController
@Slf4j
public class BusinessController {

    private static final String ACCESS_TOKEN_URL = "http://localhost:8080/oauth/token";

    private static final String REFRESH_TOKEN_URL = "http://localhost:8080/oauth/token";

    private static final String RESOURCE_URL = "http://localhost:8082/customerinfo";

    private static final Integer RESPONSE_OK = 200;

    private static TokenResponse cache = null;

    @RequestMapping(path = "/code2token")
    public TokenResponse code2Token(@RequestParam(value = "code") String code) {
        CloseableHttpClient httpCilent = HttpClients.createDefault();
        String accessTokenRrl =
                ACCESS_TOKEN_URL + "?client_id=client&client_secret=secret&code=" + code + "&grant_type=authorization_code&redirect_uri=http://localhost:8081/code2token";

        HttpGet httpGet = new HttpGet(accessTokenRrl);
        try {
            CloseableHttpResponse response = httpCilent.execute(httpGet);
            HttpEntity entity = response.getEntity();
            String srtResult = EntityUtils.toString(entity);
            JSONObject jsonObject = new JSONObject(srtResult);
            return cache = TokenResponse.builder()
                    .access_token(jsonObject.getString("access_token"))
                    .expires_in(jsonObject.getInt("expires_in"))
                    .refresh_token(jsonObject.getString("refresh_token"))
                    .scope(jsonObject.getString("scope"))
                    .token_type(jsonObject.getString("token_type"))
                    .build();
        } catch (IOException e) {
            log.error("", e);
        } finally {
            try {
                httpCilent.close();
            } catch (IOException e) {
                log.error("", e);
            }
        }
        return null;
    }

    @RequestMapping(path = "/customerinfo")
    public Customer getCustomer() {
        CloseableHttpClient httpCilent = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(RESOURCE_URL);
        httpGet.addHeader("Authorization", "bearer " + cache.getAccess_token());
        try {
            CloseableHttpResponse response = httpCilent.execute(httpGet);
            HttpEntity entity = response.getEntity();
            String srtResult = EntityUtils.toString(entity);
            JSONObject jsonObject = new JSONObject(srtResult);
            if ("invalid_token".equalsIgnoreCase(jsonObject.optString("error"))) {
                refreshToken();
                return getCustomer();
            } else {
                return Customer.builder()
                        .name(jsonObject.getString("name"))
                        .age(jsonObject.getInt("age"))
                        .build();
            }
        } catch (IOException e) {
            log.error("", e);
        } finally {
            try {
                httpCilent.close();
            } catch (IOException e) {
                log.error("", e);
            }
        }
        return null;
    }

    private void refreshToken() {
        CloseableHttpClient httpCilent = HttpClients.createDefault();
        String accessTokenRrl =
                REFRESH_TOKEN_URL + "?client_id=client&client_secret=secret&grant_type=refresh_token&refresh_token=" + cache.getRefresh_token();

        HttpGet httpGet = new HttpGet(accessTokenRrl);
        try {
            CloseableHttpResponse response = httpCilent.execute(httpGet);
            HttpEntity entity = response.getEntity();
            String srtResult = EntityUtils.toString(entity);
            JSONObject jsonObject = new JSONObject(srtResult);
            cache = TokenResponse.builder()
                    .access_token(jsonObject.getString("access_token"))
                    .expires_in(jsonObject.getInt("expires_in"))
                    .refresh_token(jsonObject.getString("refresh_token"))
                    .scope(jsonObject.getString("scope"))
                    .token_type(jsonObject.getString("token_type"))
                    .build();
        } catch (IOException e) {
            log.error("", e);
        } finally {
            try {
                httpCilent.close();
            } catch (IOException e) {
                log.error("", e);
            }
        }
    }
}
